﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Cofe.Core;
using Cofe.Core.Filter;
using Cofe.Core.Interfaces;
using Cofe.Core.Property;
using Cofe.Core.Service;

namespace Cofe.Data.Implements
{
    public abstract class DBPropertyProviderBase : PropertyProviderBase<IPropertyHost>
    {
        #region Constructor

        public DBPropertyProviderBase(IPropertyHost entity, IRepositoryFactory repositoryFactory, 
            params IPropertyDefinitions[] supportedDefinitions)
            : base(entity, supportedDefinitions)
        {
            if (entity == null)
                throw new ArgumentNullException("entity");
            if (repositoryFactory == null)
                throw new ArgumentNullException("repositoryFactory");
            _repositoryFactory = repositoryFactory;
        }

        #endregion

        #region Methods

        protected void registerDBProperties<T>(object prop, Func<IRepository, DatabaseEntry, T> propGetter, Func<T> defValueFunc,
            Func<IRepository, DatabaseEntry, T, bool> propSetter = null)            
        {

            Func<object> getter = () =>
            {
                string parseName = Entity.Behaviors.GetProperty<string>(CofeProperties.FullParseName);
                using (var repository = _repositoryFactory.CreateRepository())
                {
                    var dbEntry = repository.FindDbEntry(FilterCollections.FromParseName(parseName)).FirstOrDefault();
                    if (dbEntry != null)
                        return propGetter(repository, dbEntry);
                    else return defValueFunc();
                }
            };

            Func<PropertyPair, bool> setter = null;

            if (propSetter != null)
                setter = (pp) =>
                    {
                        string parseName = Entity.Behaviors.GetProperty<string>(CofeProperties.FullParseName);
                        using (var repository = _repositoryFactory.CreateRepository())
                        {
                            var dbEntry = repository.FindDbEntry(FilterCollections.FromParseName(parseName)).FirstOrDefault();
                            if (dbEntry != null)
                                return propSetter(repository, dbEntry, pp.ValueAs<T>());                            
                            return false;
                        }
                    };

            registerProperties(prop, getter,setter);
        }

        protected void registerDBProperties<T>(object prop, Func<DatabaseEntry, T> propGetter, Func<T> defValueFunc,
            Func<DatabaseEntry, T, bool> propSetter = null)
        {
            registerDBProperties<T>(prop, (r, dbEntry) => propGetter(dbEntry), defValueFunc, (r, dbEntry, val) => propSetter(dbEntry, val));
        }

        protected void registerDBAction(object property, Action<ParameterDic, IRepository> actionFunc, bool? defaultHandled = null)
        {
            registerAction(property, (pd) =>
                {
                    if (defaultHandled.HasValue)
                        pd.IsHandled = defaultHandled.Value;
                    using (var repository = _repositoryFactory.CreateRepository())
                        actionFunc(pd, repository);
                });
        }

        protected void registerDBAction<T>(object property, Func<ParameterDic, IRepository, T> actionFunc, bool? defaultHandled = null)
        {
            registerAction<T>(property, (pd) =>
                {
                    if (defaultHandled.HasValue)
                        pd.IsHandled = defaultHandled.Value;
                    using (var repository = _repositoryFactory.CreateRepository())
                        return actionFunc(pd, repository);
                });
        }
        
        #endregion

        #region Data

        protected IRepositoryFactory _repositoryFactory;

        #endregion

        #region Public Properties
        
        #endregion

    }
}
